/***************************************************************************
*  Lowlayer.hpp
*
*  July 2007
*  Copyright  2007  RuijinZheng,China
*  Email mebetop@126.com
****************************************************************************/

/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
#ifndef LOWLAYER_HPP
#define LOWLAYER_HPP
#include <iostream>
using namespace std;
#include <cstdio>
#include <string>
#include <arpa/inet.h>
#include <netdb.h>
#include <vector>
#include <cstring>
#include <fcntl.h>
#include <cerrno>
#include <ctime>
////////////////////////////
/// ------------> 
///define the orignal functions pointer in libc,like connect gethostbyname ,etc.
//typedef struct hostent *(*old_gethostbyname)(const char *hostname);
///gethostbyname defined in netdb.h
//typedef struct hostent *(*old_gethostbyname2)(char *name,int family);
///gethostbyname2 defined in netdb.h
//typedef int (*old_socket)(int family,int type,int protocol);//socket in  sys/socket.h
typedef int(*old_connect)(int  sockfd,  const  struct sockaddr *serv_addr,socklen_t  addrlen);
///connect defined int sys/socket.h
//typedef int (*old_accept)(int sockfd,struct sockaddr *cliaddr,socklen_t *addrlen);
///accept defined in sys/socket.h
typedef int (*old_bind)(int sockfd,const struct sockaddr *myaddr,socklen_t addrlen);
///bind defined in sys/socket.h
typedef int (*old_read)(int sockfd,char *buff,int bufflen);
///read defined in unistd.h
typedef int (*old_recv)(int sockd,char *buff,int buflen,int flags);
///recv defined in sys/socket.h
typedef ssize_t (*old_recvfrom)(int sockfd,void *buff,size_t buflen,int flags,sockaddr *from,socklen_t *fromlen);
///recvfrom defined in sys/socket.h
typedef int (*old_write)(int sockfd,char *buf,int buflen);
///write defined in unistd.h
typedef int (*old_send)(int sockfd,char *buff,int buflen,int flags);
///send defined in sys/socket.h
typedef ssize_t (*old_sendto)(int sockfd,const void*buff,size_t buflen,int flags,const sockaddr  *to,socklen_t  tolen);
///sendto defined in sys/socket.h
//typedef int (*old_close)(int sockfd);
///close defined in sys/socket.h
//typedef int (*old_getsockname)(int sockfd,struct sockaddr *localaddr,socklen_t *addrlen);
///getsockname defined in sys/socket.h
//typedef int (*old_getpeername)(int sockfd,struct sockaddr *peeraddr,socklen_t *addrlen);
///getpeername defined in sys/socket.h
//typedef int select(int maxfd,fd_set *read_set,fd_set *write_set,fd_set *except_set,const struct timeval *timecout);
/// select defined in sys/select.h relates with sys/time.h
////////////////////////////
////////////////////////////
/////////////////////////
/// <-------------define the orignal functions pointer in libc,like connect

#define BUFFERSIZE 255 
/// define max size  for common use of buffer
#define UDPTCPBUFFERSIZE 1024 
/// define max size  for bigger requirement in size of buffer 
#define UDPBUFFERSIZE 8192 
/// define max size of buffer for udp

//#ifndef SHOWDEBUGINFO 
///    decide  wheather show debug message or not
//#define SHOWDEBUGINFO
//#endif
#define FIFO_FILE  "/tmp/NETFLEAFIFO"
//////////////////////////////
//////////////////////////////
struct Proxyserver
{ 
/// structrue storages the proxy server attributes,
/// 
       string sType;
       string sServername;
       int    iPort;
       string sUser;
       string sPasswd;
	
};
struct Udpproxy
{
/// used in udp cases,being the record of information  of a tcp connect,
/// which is used to begin a udp communication 
       int tcpsocket;
       int addrtype;
       int bindport;
       string bindip;
};
//////////////////////////////
//////////////////////////////
class Lowlayer 
{

public:

         Lowlayer(const old_connect *origconnect,const old_recv *origrecv,const old_send *origsend,
const old_recvfrom *origrecvfrom,const old_sendto *origsendto) throw (const string &);

         virtual ~Lowlayer();

         virtual const Proxyserver *Getproxyserver(const vector<Proxyserver> &availableserver)=0;
         virtual int Connectflea(const int &sockfd,const  sockaddr *serv_addr,const vector<Proxyserver> &availableserver)=0;


         static bool Errordeliver(const string operation,const string errormsg);

         bool Acthttpproxy(const int &sock,const sockaddr_in &in,const string &username,
              const string &password);
         bool Actsocks4proxy(const int &sock,const sockaddr_in &in);
         bool Actsocks4aproxy(const int &sock,const sockaddr_in &in);
         bool Actsocks5proxy(const int &sock,const sockaddr_in &in);
         bool Prepareforsocks5proxy(const int &sock,const string &username,
              const string &password);

protected:

         int  Connecttoserver(const int &sock,const string &proxyserverip,const int &proxyport);
         bool Sendtoserver(const int &sock,const char * buf, int buflen);
         int  Recvfromserver(const int &sock,char *buf,int buflen);

         bool Formaddr_in(const string &host,const int &port,sockaddr_in &in);

         int  Makesocks4request(unsigned char *buff,const sockaddr_in &in);
         int  Makesocks4arequest(unsigned char *buff,const sockaddr_in &in);
         int  Makesocks5methodrequest(unsigned char *buff);
         int  Makesocks5authrequest(unsigned char *buff,const char *username,
              const char *password);
         int  Makesocks5destrequest(unsigned char *buff, const sockaddr_in &in);
         int  Makesocks5destrequest_udp(unsigned char *buff, const sockaddr_in &in);
private:

         string getipfromaddr_in(const struct sockaddr_in &in);
         int getportfromaddr_in(const struct sockaddr_in &in);
         sa_family_t getfamilyfromaddr_in(const struct sockaddr_in &in);

         int Base64Enc(char *dest,const  char*origtext,int size);

protected:

         const old_recvfrom *oldrecvfrom;
         const old_sendto *oldsendto;

private:

         const old_connect *oldconnect;
         const old_recv *oldrecv;
         const old_send *oldsend;

         unsigned  int utimeout;

};
#endif
